`define ADDR_W $clog2(DEPTH)

/**
 * Instruction sram-like interface Data response Buffer (circular queue)
 * +-----------+
 * |           |
 * +-----------+
 * |           | <- head (next pop item)
 * +-----------+
 * |           | 
 * +-----------+
 * |           |
 * +-----------+
 * |           | <- tail (empty item)
 * +-----------+
 */

module idb #(
  parameter DEPTH = 4,
  parameter WIDTH = 32
) (
  input clk,
  input rst,

  // write port (when addr_ok, write instructions in the buffer)
  input             wvalid,
  output            wready,
  input [WIDTH-1:0] wdata ,

  // pop port
  output             pvalid,
  input              pready,
  output [WIDTH-1:0] pdata 
);
  // when the most signidicant bit of head and tail are equal,
  // the fifo might be empty, or it might be full.
  reg [`ADDR_W:0] head;
  reg [`ADDR_W:0] tail;

  wire empty;
  wire full;

  assign empty = head == tail;
  assign full = (head[`ADDR_W] ^ tail[`ADDR_W]) && (head[`ADDR_W-1:0] == tail[`ADDR_W-1:0]);

  reg [WIDTH-1:0] fifo [DEPTH-1:0];

  always@(posedge clk) begin
    if (rst) begin
      tail <= 0;
    end else if (wvalid && wready) begin
      tail <= tail + 1;
    end
  end

  always@(posedge clk) begin
    if (rst) begin
      head <= 0;
    end else if (pvalid && pready) begin
      head <= head + 1;
    end
  end

  always@(posedge clk) begin
    // avoid overwrite when fifo full
    if (wvalid && wready) begin
      fifo[tail[`ADDR_W-1:0]] <= wdata;
    end
  end

  assign pvalid = ~empty;
  assign pdata = fifo[head[`ADDR_W-1:0]];

  assign wready = ~full;
  
endmodule